#include "core/packet.h"
#include "utils/logger.h"
#include "network/protocols.h"

Packet::Packet(const uint8_t* data, std::size_t length, TimePoint timestamp) : m_length(length), m_timestamp(timestamp) {
    m_data = std::make_unique<uint8_t[]>(length);
    memcpy(m_data.get(), data, length);
}

bool Packet::parse() {
    LOG_DEBUG("Parse function called");
    // check length
    if (m_length < sizeof(EthHeader)) {
        LOG_DEBUG("Packet too short to contain Ethernet header.");
        return false;
    }

    // parse ethernet level
    m_ethHeader = reinterpret_cast<const EthHeader*>(m_data.get());
    if (!m_ethHeader) {
        LOG_DEBUG("Ethernet header is null.");
        return false;
    }

    // According to ethernet type to parse upper protocol.
    uint8_t* nextHeader = m_data.get() + sizeof(EthHeader);
    std::size_t remainingLength = m_length - sizeof(EthHeader);

    // parse IP level
    if (m_ethHeader->isIPv4()) {
        // parse ipv4
        if (remainingLength < sizeof(IPv4Header)) {
            LOG_DEBUG("Packet too short to contain IPv4 header.");
            return false;
        }

        m_ipv4Header = reinterpret_cast<const IPv4Header*>(nextHeader);
        uint8_t ipHeaderLength = m_ipv4Header->headerLength();

        if (ipHeaderLength < sizeof(IPv4Header)) {
            LOG_DEBUG("IPv4 header length too short.");
            return false;
        }

        if (remainingLength < ipHeaderLength) {
            LOG_DEBUG("Packet too short for claimed IPv4 header length.");
            return false;
        }

        // transaction level
        nextHeader += ipHeaderLength;
        remainingLength -= ipHeaderLength;

        if (m_ipv4Header->isTCP() && remainingLength >= sizeof(TCPHeader)) {
            m_tcpHeader = reinterpret_cast<const TCPHeader*>(nextHeader);
            uint8_t tcpHeaderLength = m_tcpHeader->headerLength();

            if (tcpHeaderLength < sizeof(TCPHeader) || remainingLength < tcpHeaderLength) {
                LOG_DEBUG("Tcp header length invalid or packet too short.");
                return false;
            }

            // application level
            m_payload = nextHeader + tcpHeaderLength;
            m_payloadLength = remainingLength - tcpHeaderLength;
        } else if (m_ipv4Header->isUDP() && remainingLength >= sizeof(UDPHeader)) {
            m_udpHeader = reinterpret_cast<const UDPHeader*>(nextHeader);

            // application level
            m_payload = nextHeader + sizeof(UDPHeader);
            m_payloadLength = remainingLength - sizeof(UDPHeader);

            // check whether UDP length is correct
            if (ntohs(m_udpHeader->length) != remainingLength + sizeof(UDPHeader)) {
                LOG_DEBUG("UDP length field doesn't match actual length.");
            }
        }
        // other protocol
    } else if (m_ethHeader->isIPv6()) {
        LOG_DEBUG("IPv6 packet.");
    } else {
        LOG_DEBUG("Other packet");
    }
    return true;
}